"""
DI 引擎 - 专用装饰器
"""
from functools import wraps
from typing import Any, Callable, List, Optional, Type


def order(value: int) -> Callable[[Any], Any]:
    """
    一个类/函数装饰器，用于指定服务或处理器的加载/执行顺序。
    数值越小，优先级越高。
    """
    def decorator(decorated_class: Any) -> Any:
        setattr(decorated_class, '_axiom_order', value)
        return decorated_class
    return decorator


def service(
    name: Optional[str] = None,
    provides: Optional[Type] = None,
    condition: Optional[Callable[[Any], bool]] = None
) -> Callable[[Any], Any]:
    """
    将一个类或工厂函数标记为可注入的服务。

    Args:
        name: (可选) 为该服务指定一个唯一的名称。如果没有提供，
              将使用类名/函数名的小写版本作为名称。
        provides: (可选) 显式声明此服务提供的类型。当装饰的是一个
                  返回接口或抽象基类的工厂函数时，此参数至关重要。
        condition: (可选) 一个条件函数，它接收 Settings 对象并返回布尔值。
                   只有当此函数返回 True 时，该服务才会被注册。

    Returns:
        返回被装饰的目标，并附加 DI 相关的元数据属性。
    """
    def decorator(target: Any) -> Any:
        setattr(target, '_axiom_is_service', True)
        setattr(target, '_axiom_service_name', name)
        setattr(target, '_axiom_service_provides', provides)
        setattr(target, '_axiom_service_condition', condition)
        return target
    return decorator


def mapper(
    name: Optional[str] = None,
    provides: Optional[Type] = None
) -> Callable[[Type], Type]:
    """
    将一个类标记为数据映射器 (Mapper/DAO)。

    这在功能上与 @service 类似，但提供了更明确的语义，
    表明该类负责数据访问层的操作。

    Args:
        name: (可选) 为该映射器指定一个唯一的名称。如果没有提供，
              将使用类名的小写版本作为名称。
        provides: (可选) 显式声明此映射器提供的类型。

    Returns:
        返回被装饰的类，并附加 DI 相关的元数据属性。
    """
    def decorator(cls: Type) -> Type:
        # 在内部，它和 service 是一样的处理方式
        setattr(cls, '_axiom_is_service', True)
        setattr(cls, '_axiom_service_name', name)
        setattr(cls, '_axiom_service_provides', provides)
        # Mapper 通常不是条件化的，但为保持一致性，可以设为 None
        setattr(cls, '_axiom_service_condition', None)
        return cls
    return decorator


def conditional_on_setting(
    key: str,
    expected_value: Any = True,
    match_if_present: bool = False,
    negate: bool = False
) -> Callable[[Type], Type]:
    """
    一个条件化装饰器，仅当配置满足特定条件时，才会加载该服务。
    此装饰器可以被堆叠使用，目标服务必须满足所有条件才会被加载。

    Args:
        key: Settings 对象中的配置项的键 (例如, "oauth_enabled")。
        expected_value: (可选) 配置项期望的值。默认为 True。
        match_if_present: (可选) 如果为 True, 则只要配置项存在且不为 None, 条件就满足。
                          此时将忽略 expected_value。默认为 False。
        negate: (可选) 如果为 True, 则会对最终的条件判断结果取反。
                例如，当 key 的值为 False 时，条件反而满足。

    Returns:
        返回被装饰的类，并附加条件化加载所需的元数据。
    """
    def decorator(cls: Type) -> Type:
        # 确保只在目标上创建一次列表
        if not hasattr(cls, '_axiom_conditional_on_setting_list'):
            setattr(cls, '_axiom_conditional_on_setting_list', [])
        
        # 将新的条件元组追加到列表中
        condition_tuple = (key, expected_value, match_if_present, negate)
        getattr(cls, '_axiom_conditional_on_setting_list').append(condition_tuple)
        
        return cls
    return decorator


def controller(
    prefix: str = "",
    tags: Optional[List[str]] = None
) -> Callable[[Type], Type]:
    """
    将一个类标记为控制器，并可选择性地配置路由前缀和标签。

    Args:
        prefix: (可选) 此控制器下所有路由的 URL 前缀。
        tags: (可选) 用于在 API 文档中分组的标签列表。

    Returns:
        返回被装饰的类，并附加控制器相关的元数据。
    """
    def decorator(cls: Type) -> Type:
        setattr(cls, '_axiom_is_controller', True)
        setattr(cls, '_axiom_controller_prefix', prefix)
        setattr(cls, '_axiom_controller_tags', tags or [])
        return cls
    return decorator


def route(
    path: str,
    methods: Optional[List[str]] = None,
    **kwargs: Any
) -> Callable:
    """
    将一个控制器类的方法标记为一个路由端点。

    Args:
        path: 路由的 URL 路径。
        methods: (可选) 一个 HTTP 方法的列表 (例如 ['GET', 'POST'])。
                 如果未提供，默认为 ['GET']。
        **kwargs: 其他传递给 FastAPI 的 `add_api_route` 的参数
                  (例如 status_code, response_model 等)。

    Returns:
        返回一个装饰器，该装饰器会将路由信息附加到被装饰的方法上。
    """
    def decorator(endpoint: Callable) -> Callable:
        # 确保只在函数上附加一次列表
        if not hasattr(endpoint, '_axiom_route_info'):
            setattr(endpoint, '_axiom_route_info', [])

        # 将路由信息保存起来，待 ControllerProcessor 处理
        route_info = {
            'path': path,
            'methods': methods or ['GET'],
            **kwargs
        }
        
        # 将新的路由信息追加到列表中
        getattr(endpoint, '_axiom_route_info').append(route_info)

        return endpoint
    return decorator


# 为常见的 HTTP 方法提供便捷装饰器
def get(path: str, **kwargs: Any) -> Callable:
    return route(path, methods=['GET'], **kwargs)

def post(path: str, **kwargs: Any) -> Callable:
    return route(path, methods=['POST'], **kwargs)

def put(path: str, **kwargs: Any) -> Callable:
    return route(path, methods=['PUT'], **kwargs)

def delete(path: str, **kwargs: Any) -> Callable:
    return route(path, methods=['DELETE'], **kwargs)

def patch(path: str, **kwargs: Any) -> Callable:
    return route(path, methods=['PATCH'], **kwargs)

def head(path: str, **kwargs: Any) -> Callable:
    return route(path, methods=['HEAD'], **kwargs)

def options(path: str, **kwargs: Any) -> Callable:
    return route(path, methods=['OPTIONS'], **kwargs)

def primary(cls: Type) -> Type:
    """
    一个类装饰器，用于在存在多个实现的情况下，
    将该服务标记为首选的注入候选项。

    当一个接口有多个可用的服务实现时，被 @primary 标记的
    那一个将会被默认注入。

    用法:
        @primary
        @service
        class RedisCacheService(CacheService):
            ...
    """
    setattr(cls, '_axiom_is_primary', True)
    return cls 